#import "L0PlugSuitInjector.h"
#import "L0PlugSuitRegistry.h"
#import <sys/types.h>

#import "mach_inject_bundle.h"

#import "L0PlugSuitFlavor.h"

@implementation L0PlugSuitInjector

- (oneway void) shutDown {
	[NSApp terminate:self];
}

- (void) awakeFromNib {
	[[[NSWorkspace sharedWorkspace] notificationCenter]
		addObserver:self selector:@selector(_applicationDidLaunch:) name:NSWorkspaceDidLaunchApplicationNotification object:nil];
	
	NSConnection* con = [NSConnection defaultConnection];
	[con setRootObject:self];
	
#ifdef L0PlugSuitDebug
	BOOL result =
#endif
	[con registerName:kL0PlugSuitConnectionName];
	
#ifdef L0PlugSuitDebug
	NSLog(@"Registered as %@ with result: %d", kL0PlugSuitConnectionName, result);
#endif
}

- (void) _applicationDidLaunch:(NSNotification*) notif {
	NSString* bundleID = [[notif userInfo] objectForKey:@"NSApplicationBundleIdentifier"];
	if ([bundleID isEqual:[[NSBundle mainBundle] bundleIdentifier]]) {
        // do NOT self-inject!
        return;
    } else if ([bundleID isEqual:@"com.apple.systempreferences"]) {
		// do not inject in System Preferences
		return;
	}
    
#ifdef L0PlugSuitDebug
	NSLog(@"DEBUG: Application launch notification received: %@", notif);
#endif
    
	[L0PlugSuitRegistry updateRegistries];
    
    NSBundle* app = [NSBundle bundleWithPath:
		[[notif userInfo] objectForKey:@"NSApplicationPath"]];
	NSNumber* pidNumber = [[notif userInfo] objectForKey:@"NSApplicationProcessIdentifier"];
	if (!pidNumber) return;
	pid_t pid = [pidNumber intValue];
	
	if (app && [L0PlugSuitRegistry plugInsExistFor:app processID:pid]) {
		NSString* path = [[self class] pathToSupportBundle];
		mach_error_t err = mach_inject_bundle_pid([path fileSystemRepresentation], pid);
			
		if (err)
			NSLog(@"Could not inject the support code in application %@ (with pid %d) with error code %d (%@).", app, pid, err, [self descriptionForError:err]);
#ifdef L0PlugSuitDebug
		else
			NSLog(@"DEBUG: Injected successfully in application %@ (pid %d).", app, pid);
#endif
	}
#ifdef L0PlugSuitDebug
	else
		NSLog(@"DEBUG: No plug-ins found for this application.");
#endif
}

- (NSString*) descriptionForError:(mach_error_t) err {   
    switch (err) {
        case err_mach_inject_bundle_couldnt_find_injection_bundle:
            return @"The injection bundle cannot be found";
        case err_mach_inject_bundle_couldnt_find_inject_entry_symbol:
            return @"The entry symbol in the injection bundle cannot be found";
        case err_mach_inject_bundle_couldnt_load_framework_bundle:
            return @"The framework bundle cannot be loaded";
        case err_mach_inject_bundle_couldnt_load_injection_bundle:
            return @"The injection bundle cannot be loaded";
		case 5:
			return @"PlugSuit was blocked by OS X's security.";
        default:
            return @"I don't know what kind of error it is.";
    }
}

+ (NSString*) pathToSupportBundle {
    static NSString* _path = nil;
    if (!_path)
        _path = [[[NSBundle mainBundle] pathForResource:@"PlugSuitSupport" ofType:@"bundle"] retain];
    return _path;
}

@end
